home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2001 December
/
pcwk12201b.iso
/
Wersje pelne i specjalne
/
Winamp 2.77 i 3.0beta
/
wasabi-sdk_beta1.exe
/
studio
/
common
/
scbkgwnd.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2001-10-08
|
19KB
|
741 lines
/*
Nullsoft WASABI Source File License
Copyright 1999-2001 Nullsoft, Inc.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Brennan Underwood
brennan@nullsoft.com
*/
#include <windows.h>
#include <commctrl.h>
#include "../common/scbkgwnd.h"
#define SCROLLBAR_SEP 4
#define TIMER_SMOOTHSCROLLY 8873
#define TIMER_SMOOTHSCROLLX 8874
#define SMOOTH_STEPS 5
ScrlBkgWnd::ScrlBkgWnd() {
inDestroy = FALSE;
bmp = NULL;
bgColor = CLR_NONE;
hScroll = NULL;
vScroll = NULL;
hSep = NULL;
vSep = NULL;
scrollX = 0;
scrollY = 0;
dbbuffer=1;
needSetSliders=FALSE;
lineHeight = 16;
wantsep=0;
lastratio = 1.0;
MEMSET(&smsqr, 0, sizeof(RECT));
}
ScrlBkgWnd::~ScrlBkgWnd() {
inDestroy = TRUE;
if (hScroll) delete hScroll;
hScroll = NULL;
if (vScroll) delete vScroll;
vScroll = NULL;
if (hSep) delete hSep;
hSep = NULL;
if (vSep) delete vSep;
vSep = NULL;
}
ScrlBkgWnd::onInit() {
SCRLBKGWND_PARENT::onInit();
scrollY=0;
scrollX=0;
hScroll = new ScrollBar();
hSep = new SepWnd();
hSep->setOrientation(SEP_HORIZONTAL);
hScroll->setBitmaps("studio.scrollbar.horizontal.left", "studio.scrollbar.horizontal.left.pressed", "studio.scrollbar.horizontal.left.hilite",
"studio.scrollbar.horizontal.right", "studio.scrollbar.horizontal.right.pressed", "studio.scrollbar.horizontal.right.hilite",
"studio.scrollbar.horizontal.button", "studio.scrollbar.horizontal.button.pressed", "studio.scrollbar.horizontal.button.hilite");
vScroll = new ScrollBar();
vSep = new SepWnd();
vSep->setOrientation(SEP_VERTICAL);
vScroll->setBitmaps("studio.scrollbar.vertical.left", "studio.scrollbar.vertical.left.pressed", "studio.scrollbar.vertical.left.hilite",
"studio.scrollbar.vertical.right", "studio.scrollbar.vertical.right.pressed", "studio.scrollbar.vertical.right.hilite",
"studio.scrollbar.vertical.button", "studio.scrollbar.vertical.button.pressed", "studio.scrollbar.vertical.button.hilite");
// hScroll->setVertical(FALSE);
vScroll->setVertical(TRUE);
hScroll->setStartHidden(TRUE); // prevent showing window at creation
vScroll->setStartHidden(TRUE);
hSep->setStartHidden(TRUE);
vSep->setStartHidden(TRUE);
hScroll->setParent(this);
vScroll->setParent(this);
hSep->setParent(this);
vSep->setParent(this);
hScroll->init(gethInstance(), gethWnd());
vScroll->init(gethInstance(), gethWnd());
hSep->init(gethInstance(), gethWnd());
vSep->init(gethInstance(), gethWnd());
hScroll->setPosition(0);
vScroll->setPosition(0);
setSlidersPosition(); // position sliders and show them if needed
return 1;
}
void ScrlBkgWnd::setBgBitmap(char *b) {
bmp = b;
if (b)
setBgColor(CLR_NONE);
}
void ScrlBkgWnd::setBgColor(COLORREF rgb) {
bgColor = rgb;
}
SkinBitmap *ScrlBkgWnd::getBgBitmap(void) {
return bmp;
}
COLORREF ScrlBkgWnd::getBgColor(void) {
return bgColor;
}
// Scroll to a specified Y-pixels
void ScrlBkgWnd::scrollToY(int y, int signal) {
WndCanvas *canvas=NULL;
RECT r;
int offset;
if (ABS(getRenderRatio() - 1.0) > 0.01) {
scrollY=y;
getClientRect(&r);
invalidateRect(&r);
return;
}
if (y>scrollY) { // tree scrolling up, scroller going down. invalidating from the bottom. bitblting from bottom to top
int lines = y-scrollY;
offset=-lines;
getClientRect(&r);
canvas = new WndCanvas();
canvas->attachToClient(this);
Region *reg = new Region();
makeWindowOverlayMask(reg);
Region *clip = new Region(&r);
reg->offset(0, offset);
clip->subtract(reg);
canvas->selectClipRgn(clip);
canvas->blit(r.left, r.top+lines, canvas, r.left, r.top, r.right-r.left, r.bottom-r.top-lines);
canvas->selectClipRgn(NULL);
if (!reg->isEmpty())
invalidateRgn(reg);
delete clip;
delete reg;
r.top = r.bottom-lines;
}
if (y<scrollY) { // tree scrolling down, scroller going up. invalidating from the top. bitblting from top to bottom
int lines = scrollY-y;
offset=lines;
getClientRect(&r);
canvas = new WndCanvas();
canvas->attachToClient(this);
Region *reg = new Region();
makeWindowOverlayMask(reg);
Region *clip = new Region(&r);
reg->offset(0, offset);
clip->subtract(reg);
canvas->selectClipRgn(clip);
canvas->blit(r.left, r.top, canvas, r.left, r.top+lines, r.right-r.left, r.bottom-r.top-lines);
canvas->selectClipRgn(NULL);
if (!reg->isEmpty())
invalidateRgn(reg);
delete clip;
delete reg;
r.bottom = r.top+lines+1;
}
if (canvas) {
delete canvas;
scrollY=y;
// in case we have a virtualCanvas, we need to tell BaseWnd to call us to paint on it next time it's needed coz we blited directly to the screen
RECT cr;
getClientRect(&cr);
RECT screenblit;
SubtractRect(&screenblit, &cr, &r);
deferedInvalidateRect(&screenblit);
// then invalidate what's needed
invalidateRect(&r);
dbbuffer = 1;
repaint();
}
if (signal)
updateVScroll(y);
}
// Scroll to a specified X-pixel
void ScrlBkgWnd::scrollToX(int x, int signal) {
WndCanvas *canvas=NULL;
RECT r;
int offset;
if (ABS(getRenderRatio() - 1.0) > 0.01) {
scrollX=x;
getClientRect(&r);
invalidateRect(&r);
return;
}
if (x>scrollX) { // tree scrolling left, scroller going right. invalidating from the right. bitblting from right to left
int lines = x-scrollX;
offset=-lines;
getClientRect(&r);
r.top-=getHeaderHeight();
canvas = new WndCanvas();
canvas->attachToClient(this);
Region *reg = new Region();
makeWindowOverlayMask(reg);
Region *clip = new Region(&r);
reg->offset(offset, 0);
clip->subtract(reg);
canvas->selectClipRgn(clip);
canvas->blit(r.left+lines, r.top, canvas, r.left, r.top, r.right-r.left-lines, r.bottom-r.top);
canvas->selectClipRgn(NULL);
if (!reg->isEmpty())
invalidateRgn(reg);
delete clip;
delete reg;
r.left = r.right-lines-1;
}
if (x<scrollX) { // tree scrolling right, scroller going left. invalidating from the left. bitblting from left to right
int lines = scrollX-x;
offset=lines;
getClientRect(&r);
r.top-=getHeaderHeight();
canvas = new WndCanvas();
canvas->attachToClient(this);
Region *reg = new Region();
makeWindowOverlayMask(reg);
Region *clip = new Region(&r);
reg->offset(offset, 0);
clip->subtract(reg);
canvas->selectClipRgn(clip);
canvas->blit(r.left, r.top, canvas, r.left+lines, r.top, r.right-r.left-lines, r.bottom-r.top);
canvas->selectClipRgn(NULL);
if (!reg->isEmpty())
invalidateRgn(reg);
delete clip;
delete reg;
r.right = r.left+lines+1;
}
if (canvas) {
delete canvas;
scrollX=x;
// in case we have a virtualCanvas, we need to tell BaseWnd to call us to paint on it next time it's needed coz we blited directly to the screen
RECT cr;
getClientRect(&cr);
cr.top-=getHeaderHeight();
RECT screenblit;
SubtractRect(&screenblit, &cr, &r);
deferedInvalidateRect(&screenblit);
// then invalidate what's needed
invalidateRect(&r);
dbbuffer = 1;
repaint();
}
if (signal)
updateHScroll(x);
}
void ScrlBkgWnd::setSlidersPosition() {
if (!gethWnd()) return;
RECT d;
getClientRect(&d);
if ((d.left >= d.right) || (d.top >= d.bottom))
return;
RECT r;
if (inDestroy) return;
if (!isVisible()) {
needSetSliders=TRUE;
return;
}
needSetSliders=FALSE;
if (needHScroll()) {
getNonClientRect(&r);
r.top = r.bottom - getScrollbarWidth();
if (needVScroll())
r.right -= getScrollbarWidth() + (wantsep ? SCROLLBAR_SEP : 0);
RECT z; hScroll->getNonClientRect(&z);
if (!EqualRect(&r, &z)) {
hScroll->resizeToRect(&r);
RECT s=r;
s.bottom = s.top;
s.top -= (wantsep ? SCROLLBAR_SEP : 0);
hSep->resizeToRect(&s);
}
if (!hScroll->isVisible()) {
hScroll->setVisible(TRUE);
if (wantsep) hSep->setVisible(TRUE);
onHScrollToggle(TRUE);
}
hScroll->setNPages(((int)(getContentsWidth() / (r.right-r.left)))+1);
hScroll->setUpDownValue((int)(((float)lineHeight / (getContentsWidth()-(r.right-r.left)))*SCROLLBAR_FULL));
hScroll->setPosition((int)((float)scrollX / getMaxScrollX() * SCROLLBAR_FULL));
} else {
if (hScroll->isVisible()) {
hScroll->setVisible(FALSE);
if (wantsep) hSep->setVisible(FALSE);
onHScrollToggle(FALSE);
}
hScroll->setPosition(0);
scrollToX(0);
}
if (needVScroll()) {
getNonClientRect(&r);
r.left = r.right - getScrollbarWidth();
if (needHScroll())
r.bottom -= getScrollbarWidth();
RECT z; vScroll->getNonClientRect(&z);
if (!EqualRect(&r, &z)) {
vScroll->resizeToRect(&r);
RECT s=r;
s.right = s.left;
s.left -= (wantsep ? SCROLLBAR_SEP : 0);
vSep->resizeToRect(&s);
}
if (!vScroll->isVisible()) {
vScroll->setVisible(TRUE);
if (wantsep) vSep->setVisible(TRUE);
onVScrollToggle(TRUE);
}
vScroll->setNPages(((int)(getContentsHeight() / (r.bottom-r.top)))+1);
vScroll->setUpDownValue((int)(((float)lineHeight / (getContentsHeight()-(r.bottom-r.top)))*SCROLLBAR_FULL));
vScroll->setPosition((int)((float)scrollY / getMaxScrollY() * SCROLLBAR_FULL));
} else {
if (vScroll->isVisible()) {
vScroll->setVisible(FALSE);
if (wantsep) vSep->setVisible(FALSE);
onVScrollToggle(FALSE);
}
vScroll->setPosition(0);
scrollToY(0);
}
if (hSep) hSep->invalidate();
if (vSep) vSep->invalidate();
if (needHScroll() && needVScroll()) {
getNonClientRect(&smsqr);
smsqr.left = smsqr.right - getScrollbarWidth();
smsqr.top = smsqr.bottom - getScrollbarWidth();
invalidateRect(&smsqr);
}
}
void ScrlBkgWnd::onHScrollToggle(BOOL set) {
}
void ScrlBkgWnd::onVScrollToggle(BOOL set) {
}
int ScrlBkgWnd::onPaint(Canvas *canvas) {
RECT d;
getClientRect(&d);
if ((d.left >= d.right) || (d.top >= d.bottom)) {
return SCRLBKGWND_PARENT::onPaint(canvas);
}
if (needSetSliders) setSlidersPosition();
RECT z;
GetUpdateRect(gethWnd(), &z, FALSE);
PaintCanvas paintcanvas;
PaintBltCanvas paintbcanvas;
if (canvas == NULL) {
if (dbbuffer) {
if (!paintbcanvas.beginPaintNC(this)) return 0;
canvas = &paintbcanvas;
} else {
if (!paintcanvas.beginPaint(this)) return 0;
canvas = &paintcanvas;
}
}
dbbuffer=1;
SCRLBKGWND_PARENT::onPaint(canvas);
Region *smsq = NULL;
if (needHScroll() && needVScroll()) {
renderBaseTexture(canvas, smsqr);
smsq = new Region(&smsqr);
}
RECT r;
getNonClientRect(&r);
RECT c={r.left,0,r.right,r.top}; // create label rect
Region *reg = new Region(&c);
Region *clip = new Region();
if (canvas->getClipRgn(clip) == 0) {
delete clip;
clip = new Region(&r);
if (smsq) clip->subtract(smsq);
canvas->selectClipRgn(clip);
} else {
clip->subtract(reg);
if (smsq) clip->subtract(smsq);
canvas->selectClipRgn(clip);
}
if (smsq) delete smsq;
drawBackground(canvas);
delete clip;
delete reg;
if (getRenderRatio() != lastratio) { invalidate(); lastratio = getRenderRatio(); } // todo: make that an event
return 1;
}
int ScrlBkgWnd::needDoubleBuffer() {
return dbbuffer;
}
int ScrlBkgWnd::onEraseBkgnd(HDC dc) {
/* DCCanvas canvas;
canvas.cloneDC(dc);
drawBackground(&canvas);*/
return 1;
}
// Draws tiled background
void ScrlBkgWnd::drawBackground(Canvas *canvas) {
RECT r;
getClientRect(&r);
if (bmp.getBitmap() && bgColor == CLR_NONE) {
r.top-=scrollY%bmp.getBitmap()->getHeight();
r.left-=scrollX%bmp.getBitmap()->getWidth();
bmp.getBitmap()->blitTile(canvas, &r);
} else if (bgColor != CLR_NONE) {
canvas->fillRect(&r, bgColor);
}
}
BOOL ScrlBkgWnd::needHScroll() {
if (!vScroll || !wantHScroll()) return FALSE;
RECT r;
getNonClientRect(&r);
if (vScroll->isVisible())
r.right -= getScrollbarWidth();
return (getContentsWidth() > r.right - r.left);
}
BOOL ScrlBkgWnd::needVScroll() {
if (!hScroll || !wantVScroll()) return FALSE;
RECT r;
getNonClientRect(&r);
r.top += getHeaderHeight();
if (hScroll->isVisible())
r.bottom -= getScrollbarWidth();
return (getContentsHeight() > r.bottom - r.top);
}
// Returns the current tree width in pixels
int ScrlBkgWnd::getContentsWidth() {
/*RECT r;
ScrlBkgWnd::getClientRect(&r);
return r.right-r.left;*/
return 10000;
}
// Returns the current tree height in pixels
int ScrlBkgWnd::getContentsHeight() {
/*RECT r;
ScrlBkgWnd::getClientRect(&r);
return r.bottom-r.top;*/
return 10000;
}
int ScrlBkgWnd::getMaxScrollY() {
RECT r;
getClientRect(&r);
return max(0, getContentsHeight()-(r.bottom-r.top));
}
int ScrlBkgWnd::getMaxScrollX() {
RECT r;
getClientRect(&r);
return max(0, getContentsWidth()-(r.right-r.left));
}
void ScrlBkgWnd::updateVScroll(int y) {
int z = (int)((float)y/getMaxScrollY()*SCROLLBAR_FULL);
vScroll->setPosition(z);
}
void ScrlBkgWnd::updateHScroll(int x) {
int z = (int)((float)x/getMaxScrollX()*SCROLLBAR_FULL);
hScroll->setPosition(z);
}
void ScrlBkgWnd::updateScrollY(int smooth) {
int y = (int)((float)(vScroll->getPosition())/SCROLLBAR_FULL * getMaxScrollY());
if (!smooth)
scrollToY(y /*& ~3*/);
else
smoothScrollToY(y);
}
void ScrlBkgWnd::updateScrollX(int smooth) {
int x = (int)((float)(hScroll->getPosition())/SCROLLBAR_FULL * getMaxScrollX());
if (!smooth)
scrollToX(x /*& ~3*/);
else
smoothScrollToX(x);
}
void ScrlBkgWnd::smoothScrollToX(int x) {
killSmoothXTimer();
smoothScrollXInc = -(float)(scrollX - x) / SMOOTH_STEPS;
smoothScrollXCur = (float)scrollX;
smoothScrollXTimerCount = 0;
smoothXTimer = 1;
setTimer(TIMER_SMOOTHSCROLLX, 25);
}
void ScrlBkgWnd::killSmoothYTimer() {
if (smoothYTimer) {
killTimer(TIMER_SMOOTHSCROLLY);
smoothScrollYCur += smoothScrollYInc * (SMOOTH_STEPS - smoothScrollYTimerCount);
scrollToY((int)smoothScrollYCur);
smoothYTimer = 0;
updateVScroll(scrollY);
}
}
void ScrlBkgWnd::killSmoothXTimer() {
if (smoothXTimer) {
killTimer(TIMER_SMOOTHSCROLLX);
smoothScrollXCur += smoothScrollXInc * (SMOOTH_STEPS - smoothScrollXTimerCount);
scrollToX((int)smoothScrollXCur);
smoothXTimer = 0;
updateHScroll(scrollX);
}
}
void ScrlBkgWnd::smoothScrollToY(int y) {
killSmoothYTimer();
smoothScrollYInc = -(float)(scrollY - y) / SMOOTH_STEPS;
smoothScrollYCur = (float)scrollY;
smoothScrollYTimerCount = 0;
smoothYTimer = 1;
setTimer(TIMER_SMOOTHSCROLLY, 25);
}
void ScrlBkgWnd::timerCallback (int id) {
switch (id) {
case TIMER_SMOOTHSCROLLY:
smoothScrollYCur += smoothScrollYInc;
scrollToY((int)smoothScrollYCur, FALSE);
if (++smoothScrollYTimerCount == SMOOTH_STEPS)
killSmoothYTimer();
return;
case TIMER_SMOOTHSCROLLX:
smoothScrollXCur += smoothScrollXInc;
scrollToX((int)smoothScrollXCur, FALSE);
if (++smoothScrollXTimerCount == SMOOTH_STEPS)
killSmoothXTimer();
return;
}
SCRLBKGWND_PARENT::timerCallback(id);
}
// Gets notification from sliders
int ScrlBkgWnd::childNotify(RootWnd *child, int msg, int param1, int param2) {
switch (msg) {
case UMSG_SCROLLBAR_SETPOSITION:
if (child == vScroll) {
updateScrollY(param1);
return 1;
}
if (child == hScroll) {
updateScrollX(param1);
return 1;
}
break;
}
return SCRLBKGWND_PARENT::childNotify(child, msg, param1, param2);
}
int ScrlBkgWnd::onResize() {
SCRLBKGWND_PARENT::onResize();
invalidateRect(&smsqr);
setSlidersPosition();
return 1;
}
void ScrlBkgWnd::onSetVisible(int show) {
if (show)
setSlidersPosition();
}
void ScrlBkgWnd::getClientRect(RECT *r) {
SCRLBKGWND_PARENT::getClientRect(r);
if (needVScroll())
r->right-=getScrollbarWidth()+(wantsep ? SCROLLBAR_SEP : 0);
if (needHScroll())
r->bottom-=getScrollbarWidth()+(wantsep ? SCROLLBAR_SEP : 0);
r->top += getHeaderHeight();
}
void ScrlBkgWnd::getNonClientRect(RECT *r) {
SCRLBKGWND_PARENT::getClientRect(r); // my non client rect is my parent's client rect
return;
}
int ScrlBkgWnd::getHeaderHeight() {
return 0;
}
void ScrlBkgWnd::setLineHeight(int h) {
lineHeight = h;
}
int ScrlBkgWnd::getLinesPerPage() {
RECT r;
getClientRect(&r);
int h = r.bottom - r.top;
return h / lineHeight;
}
int ScrlBkgWnd::getScrollX() {
return scrollX;
}
int ScrlBkgWnd::getScrollY() {
return scrollY;
}
int ScrlBkgWnd::getScrollbarWidth() {
if (hScroll) return hScroll->getWidth();
if (vScroll) return vScroll->getWidth();
return 0;
}
/*void ScrlBkgWnd::clientToScreen(RECT *r) {
POINT p;
p.x = r->left;
p.y = r->top;
SCRLBKGWND_PARENT::clientToScreen((int *)&p.x, (int*)&p.y);
r->left = p.x;
r->top = p.y;
p.x = r->right;
p.y = r->bottom;
SCRLBKGWND_PARENT::clientToScreen((int *)&p.x, (int*)&p.y);
r->right = p.x;
r->bottom = p.y;
}
void ScrlBkgWnd::clientToScreen(int *x, int *y) {
SCRLBKGWND_PARENT::clientToScreen(x, y);
}
void ScrlBkgWnd::clientToScreen(POINT *p) {
TREEWND_PARENT::clientToScreen((int *)&p->x, (int *)&p->y);
}*/
void ScrlBkgWnd::freeResources() {
SCRLBKGWND_PARENT::freeResources();
}
void ScrlBkgWnd::reloadResources() {
SCRLBKGWND_PARENT::reloadResources();
}
void ScrlBkgWnd::makeWindowOverlayMask(Region *r) {
HDC dc = GetDC(gethWnd());
if (getRandomRgn) {
RECT cr;
getClientRect(&cr);
RECT wr;
getWindowRect(&wr);
Region *sr = new Region();
getRandomRgn(dc, sr->getHRGN(), SYSRGN);
sr->offset(-wr.left, -wr.top);
r->setRect(&cr);
r->subtract(sr);
delete sr;
}
ReleaseDC(gethWnd(), dc);
}